home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Entertainment / MacMud / Mud 4.0 / object.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-03-24  |  28.7 KB  |  1,260 lines  |  [TEXT/MPS ]

  1. #include <sys/types.h>
  2. #include <types.h>
  3. #include <mac.h>
  4. #include <stdio.h>
  5. #include <string.h>
  6.  
  7. #include "config.h"
  8. #include "lint.h"
  9. #include "interpret.h"
  10. #include "object.h"
  11. #include "sent.h"
  12. #include "config.h"
  13. #include "nlhack.h"
  14. #include "wiz_list.h"
  15. #include "exec.h"
  16. #include "rc.h"
  17.  
  18. extern int d_flag;
  19. extern int total_num_prog_blocks, total_prog_block_size;
  20.  
  21. #ifndef mac
  22. #ifdef USE_TIOCGETP        /* Check if BSD */
  23. extern int getpid();
  24. #else
  25. extern pid_t getpid();
  26. #endif
  27. #endif
  28.  
  29. extern int fstat PROT((int, struct stat *));
  30. extern char *xalloc PROT((int)), *string_copy PROT((char *));
  31. extern void free_mapping PROT((struct vector *));
  32.  
  33. void remove_swap_file PROT((struct object *));
  34.  
  35. extern int atoi();
  36.  
  37. struct object *previous_ob;
  38. extern struct svalue const0;
  39.  
  40. int tot_alloc_object, tot_alloc_object_size;
  41.  
  42. /*
  43.  * Replace newlines in a string with a carriage return, to make the string
  44.  * writeable on one line.
  45.  */
  46.  
  47. static void replace_newline(str)
  48.     char *str;
  49. {
  50.     for (; *str; str++) {
  51.     if (str[0] == '\n')
  52. #ifndef MSDOS
  53.         str[0] = '\r';
  54. #else
  55.         str[0] = 30;
  56. #endif
  57.     }
  58. }
  59.  
  60. /*
  61.  * Replace carriage return in a string with newlines.
  62.  */
  63.  
  64. static void restore_newline(str)
  65.     char *str;
  66. {
  67.     for (; *str; str++) {
  68. #ifndef MSDOS
  69.     if (str[0] == '\r')
  70. #else
  71.     if (str[0] == 30)
  72. #endif
  73.         str[0] = '\n';
  74.     }
  75. }
  76.  
  77. static int my_strlen(str)
  78.     char *str;
  79. {
  80.     int sz = 0;
  81.  
  82.     while (*str) {
  83.     sz++; 
  84.     if (*str == '\"' || *str == '\\') sz++;
  85.     str++;
  86.     }
  87.     return sz;
  88. }
  89.  
  90. /*
  91.  * Similar to strcat(), but escapes all funny characters.
  92.  * Used by save_object().
  93.  * src is modified temporarily, but restored again :-(
  94.  */
  95. static void my_strcat(dest,src)
  96.     char *dest,*src;
  97. {
  98.     char *pt,*pt2,ch[2];
  99.  
  100.     pt = strchr(src,'\\'); ch[1] = 0;
  101.     pt2 = strchr(src,'\"');
  102.     if (pt2 && pt2<pt || pt == 0)
  103.     pt = pt2;
  104.     while (pt) {
  105.     ch[0] = *pt; *pt = 0; 
  106.     strcat(dest,src); strcat(dest,"\\"); strcat(dest,ch);
  107.     src = pt+1; *pt = ch[0];
  108.     pt = strchr(src,'\\'); 
  109.     pt2 = strchr(src,'\"');
  110.     if (pt2 && pt2<pt || !pt)
  111.         pt = pt2;
  112.     }
  113.     strcat(dest,src);
  114. }
  115.     
  116.  
  117. static int save_map_size PROT((struct vector *v));
  118. static char *save_mapping PROT((struct vector *v));
  119.  
  120. static int save_size(v)
  121.      struct vector *v;
  122. {
  123.   int i,siz;
  124.   char numbuf[100];
  125.  
  126.   for (i=0, siz = 0; i < v->size; i++) {
  127.     if (v->item[i].type == T_STRING) {
  128.       siz += my_strlen(v->item[i].u.string) + 3; /* my_ */
  129.     }
  130.     else if (v->item[i].type == T_POINTER) {
  131.       siz += 2 + save_size(v->item[i].u.vec) + 2 + 1;
  132.     }
  133.     else if (v->item[i].type == T_MAPPING) {
  134.       siz += 2 + save_map_size(v->item[i].u.vec) + 2 + 1;
  135.     }
  136.     else if (v->item[i].type == T_NUMBER) {
  137.       sprintf(numbuf,"%d",v->item[i].u.number);
  138.       siz += strlen(numbuf) + 1;
  139.     }
  140.     else siz += 2;
  141.   }
  142.   return siz;
  143. }
  144.  
  145. static int save_map_size(v)
  146.      struct vector *v;
  147. {
  148.   int i,siz;
  149.   char numbuf[100];
  150.   struct vector *w;
  151.  
  152.   w = v->item[1].u.vec;
  153.   v = v->item[0].u.vec;
  154.   for (i=0, siz = 0; i < v->size; i++) {
  155.     if (v->item[i].type == T_STRING) {
  156.       siz += my_strlen(v->item[i].u.string) + 3; /* my_ */
  157.     }
  158.     else if (v->item[i].type == T_POINTER) {
  159.       siz += 2 + save_size(v->item[i].u.vec) + 2 + 1;
  160.     }
  161.     else if (v->item[i].type == T_MAPPING) {
  162.       siz += 2 + save_map_size(v->item[i].u.vec) + 2 + 1;
  163.     }
  164.     else if (v->item[i].type == T_NUMBER) {
  165.       sprintf(numbuf,"%d",v->item[i].u.number);
  166.       siz += strlen(numbuf) + 1;
  167.     }
  168.     else siz += 2;
  169.     if (w->item[i].type == T_STRING) {
  170.       siz += my_strlen(w->item[i].u.string) + 3; /* my_ */
  171.     }
  172.     else if (w->item[i].type == T_POINTER) {
  173.       siz += 2 + save_size(w->item[i].u.vec) + 2 + 1;
  174.     }
  175.     else if (w->item[i].type == T_MAPPING) {
  176.       siz += 2 + save_map_size(w->item[i].u.vec) + 2 + 1;
  177.     }
  178.     else if (w->item[i].type == T_NUMBER) {
  179.       sprintf(numbuf,"%d",w->item[i].u.number);
  180.       siz += strlen(numbuf) + 1;
  181.     }
  182.     else siz += 2;
  183.   }
  184.   return siz;
  185. }
  186.  
  187. /*
  188.  * Encode an array of elements into a contiguous string.
  189.  */
  190. static char *save_array(v)
  191.      struct vector *v;
  192. {
  193.     char *buf,*tbuf,numbuf[100];
  194.     int i;
  195.     
  196.     buf = xalloc(2+save_size(v)+2+1);
  197.     
  198.     strcpy(buf,"({");
  199.     for (i=0; i < v->size; i++) {
  200.     if (v->item[i].type == T_STRING) {
  201.         strcat(buf,"\""); my_strcat(buf,v->item[i].u.string); /* my_ */
  202.         strcat(buf,"\","); 
  203.     }
  204.     else if (v->item[i].type == T_POINTER) {
  205.         tbuf = save_array(v->item[i].u.vec);
  206.         strcat(buf,tbuf); strcat(buf,",");
  207.         xfree(tbuf);
  208.     }
  209.     else if (v->item[i].type == T_MAPPING) {
  210.         tbuf = save_mapping(v->item[i].u.vec);
  211.         strcat(buf,tbuf); strcat(buf,",");
  212.         xfree(tbuf);
  213.     }
  214.     else if (v->item[i].type == T_NUMBER) {
  215.         sprintf(numbuf,"%d,",v->item[i].u.number);
  216.         strcat(buf,numbuf);
  217.     }
  218.     else strcat(buf,"0,");    /* Objects can't be saved. */
  219.     }
  220.     strcat(buf,"})");
  221.     return buf;
  222. }
  223.  
  224. /*
  225.  * Encode a mapping into a contiguous string.
  226.  */
  227. static char *save_mapping(v)
  228.      struct vector *v;
  229. {
  230.     char *buf,*tbuf,numbuf[100];
  231.     struct vector *w;
  232.     int i;
  233.     
  234.     buf = xalloc(2+save_map_size(v)+2+1);
  235.     
  236.     w = v->item[1].u.vec;
  237.     v = v->item[0].u.vec;
  238.     strcpy(buf,"([");
  239.     for (i=0; i < v->size; i++) {
  240.     if (v->item[i].type == T_STRING) {
  241.         strcat(buf,"\""); my_strcat(buf,v->item[i].u.string); /* my_ */
  242.         strcat(buf,"\":"); 
  243.     }
  244.     else if (v->item[i].type == T_POINTER) {
  245.         tbuf = save_array(v->item[i].u.vec);
  246.         strcat(buf,tbuf); strcat(buf,":");
  247.         xfree(tbuf);
  248.     }
  249.     else if (v->item[i].type == T_MAPPING) {
  250.         tbuf = save_mapping(v->item[i].u.vec);
  251.         strcat(buf,tbuf); strcat(buf,":");
  252.         xfree(tbuf);
  253.     }
  254.     else if (v->item[i].type == T_NUMBER) {
  255.         sprintf(numbuf,"%d:",v->item[i].u.number);
  256.         strcat(buf,numbuf);
  257.     }
  258.     else strcat(buf,"0:");    /* Objects can't be saved. */
  259.     if (w->item[i].type == T_STRING) {
  260.         strcat(buf,"\""); my_strcat(buf,w->item[i].u.string); /* my_ */
  261.         strcat(buf,"\","); 
  262.     }
  263.     else if (w->item[i].type == T_POINTER) {
  264.         tbuf = save_array(w->item[i].u.vec);
  265.         strcat(buf,tbuf); strcat(buf,",");
  266.         xfree(tbuf);
  267.     }
  268.     else if (w->item[i].type == T_MAPPING) {
  269.         tbuf = save_mapping(w->item[i].u.vec);
  270.         strcat(buf,tbuf); strcat(buf,",");
  271.         xfree(tbuf);
  272.     }
  273.     else if (w->item[i].type == T_NUMBER) {
  274.         sprintf(numbuf,"%d,",w->item[i].u.number);
  275.         strcat(buf,numbuf);
  276.     }
  277.     else strcat(buf,"0,");    /* Objects can't be saved. */
  278.     }
  279.     strcat(buf,"])");
  280.     return buf;
  281. }
  282.  
  283. /*
  284.  * Save an object to a file.
  285.  * The routine checks with the function "valid_write()" in /obj/master.c
  286.  * to assertain that the write is legal.
  287.  */
  288. void save_object(ob, file)
  289.     struct object *ob;
  290.     char *file;
  291. {
  292.     char *name, tmp_name[80];
  293. #ifdef NLHACK
  294.     char crap1[40];
  295. #endif /* NLHACK */
  296.     int len, i;
  297.     FILE *f;
  298.     int failed = 0;
  299.     /* struct svalue *v; */
  300.  
  301.     if (ob->flags & O_DESTRUCTED)
  302.     return;
  303. #ifdef COMPAT_MODE
  304.     if (ob->user) {
  305.     strcpy(tmp_name,ob->user->name);strcat(tmp_name,"/");
  306.     if (strncmp(file, "players/", 8) != 0 ||
  307.         strncmp(file+8, tmp_name, strlen(tmp_name)) != 0 ||
  308.         strchr(file, '.'))
  309.         {
  310.         error("Illegal save file name %s\n", file);
  311.         }
  312.     } else {
  313.     if ((strncmp(current_object->name, "obj/", 4) != 0 &&
  314.         strncmp(current_object->name, "room/", 5) != 0 &&
  315.         strncmp(current_object->name, "std/", 4) != 0)
  316. #ifdef NLHACK
  317.         || !legal_path(file))
  318. #else
  319.        ) 
  320. #endif /* NLHACK */
  321.         {
  322.         error("Illegal use of save_object()\n");
  323.         }
  324.     }
  325. #ifdef NLHACK
  326.     if ((sscanf(file, "users/%s", crap1) == 1) &&
  327.         !(ob->flags & O_ONCE_INTERACTIVE))
  328.     if (!strchr(crap1, '/'))
  329.         error("Illegal use of save_object()\n");
  330. #endif /* NLHACK */
  331. #else /* ! COMPAT_MODE */
  332.     file = check_valid_path(file, ob->eff_user, "save_object", 1);
  333.     if (file == 0)
  334.     error("Illegal use of save_object()\n");
  335. #endif /* COMPAT_MODE */
  336.     len = strlen(file);
  337.     name = (char *)alloca(len + 3);
  338.     (void)strcpy(name, file);
  339. #ifndef MSDOS
  340.     (void)strcat(name, ".o");
  341. #endif /* MSDOS */
  342.     /*
  343.      * Write the save-files to different directories, just in case
  344.      * they are on different file systems.
  345.      */
  346.     sprintf(tmp_name, "%s.tmp", name);
  347. #ifdef MSDOS
  348.     (void)strcat(name, ".o");
  349. #endif
  350.     f = fopen(tmp_name, "w");
  351.     if (f == 0) {
  352.     error("Could not open %s for a save.\n", tmp_name);
  353.     }
  354.     for (i=0; i < ob->prog->num_variables; i++) {
  355.     struct svalue *v = &ob->variables[i];
  356.     char *new_string;
  357.  
  358.     if (ob->prog->variable_names[i].type & TYPE_MOD_STATIC)
  359.         continue;
  360.     if (ob->prog->variable_names[i].type & TYPE_MOD_PRIVATE)
  361.         continue;
  362.     if (v->type == T_NUMBER) {
  363.         if (fprintf(f, "%s %d\n", ob->prog->variable_names[i].name,
  364.             v->u.number) == EOF)
  365.         failed = 1;
  366.     } else if (v->type == T_STRING) {
  367.         new_string = string_copy(v->u.string);
  368.         replace_newline(new_string);
  369.         if (fprintf(f, "%s \"%s\"\n", ob->prog->variable_names[i].name,
  370.             new_string) == EOF)
  371.         failed = 1;
  372.         xfree(new_string);
  373.  
  374. /* Saving of arrays: JnA 910520
  375. */
  376.     } else if (v->type == T_POINTER) {
  377.         new_string = save_array(v->u.vec);
  378.         replace_newline(new_string);
  379.         if (fprintf(f, "%s %s\n", ob->prog->variable_names[i].name,
  380.             new_string) == EOF)
  381.             failed = 1;
  382.         xfree(new_string);
  383.     } else if (v->type == T_MAPPING) {
  384.         new_string = save_mapping(v->u.vec);
  385.         replace_newline(new_string);
  386.         if (fprintf(f, "%s %s\n", ob->prog->variable_names[i].name,
  387.             new_string) == EOF)
  388.             failed = 1;
  389.         xfree(new_string);
  390.     }
  391.     }
  392.     (void)unlink(name);
  393. #if !defined(MSDOS) && !defined(mac)
  394.     if (link(tmp_name, name) == -1)
  395. #else
  396.     (void) fclose(f);
  397. #ifndef mac
  398.     if (rename(tmp_name,name) < 0)
  399. #else
  400.     if (macrename(tmp_name,name) < 0)
  401. #endif
  402. #endif
  403.     {
  404.     perror(name);
  405.     printf("Failed to link %s to %s\n", tmp_name, name);
  406.     add_message("Failed to save object !\n");
  407.     }
  408. #if !defined(MSDOS) && !defined(mac)
  409.     (void)fclose(f);
  410.     unlink(tmp_name);
  411. #endif
  412.     if (failed)
  413.     add_message("Failed to save to file. Disk could be full.\n");
  414. }
  415.  
  416. static char *my_string_copy(str)
  417.     char *str;
  418. {
  419.     char *apa,*cp;
  420.  
  421.     cp = apa = (char *)alloca(strlen(str)+1);
  422.     
  423.     while(*str) {
  424.     if (*str == '\\') {
  425.         *cp = str[1];
  426.         if (str[1]) str+=2;
  427.         else str++;   /* String ends with a \\ buggy probably */
  428.         cp++;
  429.     }
  430.     else { *cp = *str; cp++; str++; }
  431.     }
  432.     *cp=0;
  433.     cp = string_copy(apa);
  434.     return cp;
  435. }
  436.  
  437. static int restore_map_size PROT((char **str));
  438. static struct vector *restore_mapping PROT((char **str));
  439.  
  440. /*
  441.  * Find the size of an array. Return -1 for failure.
  442.  */
  443. static int restore_size(str)
  444.      char **str;
  445. {
  446.   char *pt,*pt2;
  447.   int siz,tsiz;
  448.  
  449.   pt = *str; 
  450.   if (strncmp(pt,"({",2)) return -1;
  451.   else pt += 2;
  452.   siz = 0;
  453.  
  454.   while ((pt) && (*pt)) {
  455.     if (pt[0] == '}') {
  456.       if (pt[1] != ')') return -1;
  457.       *str = &pt[2];
  458.       return siz;
  459.     }
  460.     if (pt[0] == '\"') {
  461.       pt2 = strchr(&pt[1],'\"');
  462.       if (!pt2) return -1;
  463.       pt2--;
  464.       while (pt2[0] == '\\') {
  465.       pt = pt2;
  466.       pt2 = strchr(&pt[2],'\"');
  467.       if (!pt2) return -1;
  468.       pt2--;
  469.       }
  470.       if (pt2[2] != ',') return -1;
  471.       siz++;
  472.       pt = &pt2[3];
  473.     }
  474.     else if (pt[0] == '(') { 
  475.       if (pt[1] == '{')
  476.       tsiz = restore_size(&pt);
  477.       else
  478.       tsiz = restore_map_size(&pt);
  479.       if (tsiz < 0)
  480.       return -1;
  481.       pt++;
  482.       siz++;
  483.     }
  484.     else {
  485.       pt2 = strchr(pt, ',');
  486.       if (!pt2)
  487.       return -1;
  488.       siz++;
  489.       pt = &pt2[1];
  490.     }
  491.   }
  492.   return -1;
  493. }
  494.  
  495. static int restore_map_size(str)
  496.      char **str;
  497. {
  498.   char *pt,*pt2;
  499.   int siz,tsiz;
  500.  
  501.   pt = *str; 
  502.   if (strncmp(pt,"([",2)) return -1;
  503.   else pt += 2;
  504.   siz = 0;
  505.  
  506.   while ((pt) && (*pt)) {
  507.     if (pt[0] == ']') {
  508.       if (pt[1] != ')') return -1;
  509.       *str = &pt[2];
  510.       return siz;
  511.     }
  512.     if (pt[0] == '\"') {
  513.       pt2 = strchr(&pt[1],'\"');
  514.       if (!pt2) return -1;
  515.       pt2--;
  516.       while (pt2[0] == '\\') {
  517.       pt = pt2;
  518.       pt2 = strchr(&pt[2],'\"');
  519.       if (!pt2) return -1;
  520.       pt2--;
  521.       }
  522.       if (pt2[2] != ':') return -1;
  523.       siz++;
  524.       pt = &pt2[3];
  525.     }
  526.     else if (pt[0] == '(') { 
  527.       if (pt[1] == '{')
  528.       tsiz = restore_size(&pt);
  529.       else
  530.       tsiz = restore_map_size(&pt);
  531.       if (tsiz < 0)
  532.       return -1;
  533.       pt++;
  534.       siz++;
  535.     }
  536.     else {
  537.       pt2 = strchr(pt, ':');
  538.       if (!pt2)
  539.       return -1;
  540.       siz++;
  541.       pt = &pt2[1];
  542.     }
  543.  
  544.     if (pt[0] == '\"') {
  545.       pt2 = strchr(&pt[1],'\"');
  546.       if (!pt2) return -1;
  547.       pt2--;
  548.       while (pt2[0] == '\\') {
  549.       pt = pt2;
  550.       pt2 = strchr(&pt[2],'\"');
  551.       if (!pt2) return -1;
  552.       pt2--;
  553.       }
  554.       if (pt2[2] != ',') return -1;
  555.       pt = &pt2[3];
  556.     }
  557.     else if (pt[0] == '(') { 
  558.       if (pt[1] == '{')
  559.       tsiz = restore_size(&pt);
  560.       else
  561.       tsiz = restore_map_size(&pt);
  562.       if (tsiz < 0)
  563.       return -1;
  564.       pt++;
  565.     }
  566.     else {
  567.       pt2 = strchr(pt, ',');
  568.       if (!pt2)
  569.       return -1;
  570.       pt = &pt2[1];
  571.     }
  572.   }
  573.   return -1;
  574. }
  575.  
  576. static struct vector *restore_array(str)
  577.      char **str;
  578. {
  579.   struct vector *v,*t;
  580.   char *pt,*pt2;
  581.   int i,siz;
  582.   
  583.   pt = *str; 
  584.   if (strncmp(pt,"({",2)) return 0;
  585.   pt2 = pt;
  586.   siz = restore_size(&pt2);
  587.   if (siz < 0) return 0;
  588.   v = allocate_array(siz);
  589.   pt+=2;
  590.  
  591.   for (i=0;i<siz;i++) {
  592.     if (!*pt) return v;
  593.     if (pt[0] == '\"') {
  594.       pt2 = strchr(&pt[1],'\"');
  595.       if (!pt2) return v;
  596.       pt2--;
  597.       while (pt2[0] == '\\') {
  598.       pt2 = strchr(&pt2[2],'\"');
  599.       if (!pt2) return v;
  600.       pt2--;
  601.       }
  602.       if (pt2[2] != ',') return v;
  603.       pt2[1] = 0;
  604.       v->item[i].type = T_STRING;
  605.       v->item[i].u.string = my_string_copy(pt+1); /* my_ */
  606.       v->item[i].string_type = STRING_MALLOC;
  607.       pt = &pt2[3];
  608.     }
  609.     else if (pt[0] == '(') {
  610.       if (pt[1] == '{') {
  611.       t = restore_array(&pt);
  612.       if (!t) return v;
  613.       v->item[i].type = T_POINTER;
  614.       v->item[i].u.vec = t;
  615.       } else {
  616.       t = restore_mapping(&pt);
  617.       if (!t) return v;
  618.       v->item[i].type = T_MAPPING;
  619.       v->item[i].u.vec = t;
  620.       }
  621.       pt++;
  622.     }
  623.     else {
  624.       pt2 = strchr(pt,',');
  625.       if (!pt2) return v;
  626.       pt2[0] = 0;
  627.       v->item[i].type = T_NUMBER;
  628.       sscanf(pt,"%d",&(v->item[i].u.number));
  629.       pt = &pt2[1];
  630.     }
  631.   }
  632.   if (strncmp(pt,"})",2)) return v;
  633.   *str = &pt[2];
  634.   return v;
  635. }
  636.  
  637. static struct vector *restore_mapping(str)
  638.      char **str;
  639. {
  640.   struct vector *v,*w,*z,*t;
  641.   char *pt,*pt2;
  642.   int i,siz;
  643.   extern struct vector *order_alist PROT((struct vector *));
  644.   extern struct vector *allocate_mapping PROT((struct vector*, struct vector*));
  645.   
  646.   pt = *str; 
  647.   if (strncmp(pt,"([",2)) return 0;
  648.   pt2 = pt;
  649.   siz = restore_map_size(&pt2);
  650.   if (siz < 0) return 0;
  651.   z = allocate_mapping(v = allocate_array(siz), w = allocate_array(siz));
  652.   pt+=2;
  653.  
  654.   for (i=0;i<siz;i++) {
  655.     if (!*pt) return z;
  656.     if (pt[0] == '\"') {
  657.       pt2 = strchr(&pt[1],'\"');
  658.       if (!pt2) return z;
  659.       pt2--;
  660.       while (pt2[0] == '\\') {
  661.       pt2 = strchr(&pt2[2],'\"');
  662.       if (!pt2) return z;
  663.       pt2--;
  664.       }
  665.       if (pt2[2] != ':') return z;
  666.       pt2[1] = 0;
  667.       v->item[i].type = T_STRING;
  668.       v->item[i].u.string = my_string_copy(pt+1); /* my_ */
  669.       v->item[i].string_type = STRING_MALLOC;
  670.       pt = &pt2[3];
  671.     }
  672.     else if (pt[0] == '(') {
  673.       if (pt[1] == '{') {
  674.       t = restore_array(&pt);
  675.       if (!t) return z;
  676.       v->item[i].type = T_POINTER;
  677.       v->item[i].u.vec = t;
  678.       } else {
  679.       t = restore_mapping(&pt);
  680.       if (!t) return z;
  681.       v->item[i].type = T_MAPPING;
  682.       v->item[i].u.vec = t;
  683.       }
  684.       pt++;
  685.     }
  686.     else {
  687.       pt2 = strchr(pt,':');
  688.       if (!pt2) return z;
  689.       pt2[0] = 0;
  690.       v->item[i].type = T_NUMBER;
  691.       sscanf(pt,"%d",&(v->item[i].u.number));
  692.       pt = &pt2[1];
  693.     }
  694.     if (!*pt) return z;
  695.     if (pt[0] == '\"') {
  696.       pt2 = strchr(&pt[1],'\"');
  697.       if (!pt2) return z;
  698.       pt2--;
  699.       while (pt2[0] == '\\') {
  700.       pt2 = strchr(&pt2[2],'\"');
  701.       if (!pt2) return z;
  702.       pt2--;
  703.       }
  704.       if (pt2[2] != ',') return z;
  705.       pt2[1] = 0;
  706.       w->item[i].type = T_STRING;
  707.       w->item[i].u.string = my_string_copy(pt+1); /* my_ */
  708.       w->item[i].string_type = STRING_MALLOC;
  709.       pt = &pt2[3];
  710.     }
  711.     else if (pt[0] == '(') {
  712.       if (pt[1] == '{') {
  713.       t = restore_array(&pt);
  714.       if (!t) return z;
  715.       w->item[i].type = T_POINTER;
  716.       w->item[i].u.vec = t;
  717.       } else {
  718.       t = restore_mapping(&pt);
  719.       if (!t) return z;
  720.       w->item[i].type = T_MAPPING;
  721.       w->item[i].u.vec = t;
  722.       }
  723.       pt++;
  724.     }
  725.     else {
  726.       pt2 = strchr(pt,',');
  727.       if (!pt2) return z;
  728.       pt2[0] = 0;
  729.       w->item[i].type = T_NUMBER;
  730.       sscanf(pt,"%d",&(w->item[i].u.number));
  731.       pt = &pt2[1];
  732.     }
  733.   }
  734.   if (strncmp(pt,"])",2)) return z;
  735.   *str = &pt[2];
  736.   t = order_alist(z);
  737.   free_mapping(z);
  738.   return t;
  739. }
  740.  
  741. int restore_object(ob, file)
  742.     struct object *ob;
  743.     char *file;
  744. {
  745.     char *name, var[100], *val, *buff, *space;
  746.     int len;
  747.     FILE *f;
  748.     struct object *save = current_object;
  749.     struct stat st;
  750.     struct variable *p;
  751.  
  752.     if (current_object != ob)
  753.     fatal("Bad argument to restore_object()\n");
  754.     if (ob->flags & O_DESTRUCTED)
  755.     return 0;
  756.  
  757. #ifndef COMPAT_MODE
  758.     file = check_valid_path(file, ob->eff_user, "restore_object", 0);
  759.     if (file == 0)
  760.     error("Illegal use of restore_object()\n");
  761. #else /* Navigator 5-07-92: Problem with restoring other people's mail */
  762. #ifdef NLHACK
  763.     if (ob->user) {
  764.     if ((strncmp(file, "room/post_dir/", 14) == 0 &&
  765.         strncmp(file+14, ob->user->name, strlen(ob->user->name)) != 0) ||
  766.         strchr(file, '.'))
  767.         {
  768.         error("Illegal restore file name %s\n", file);
  769.         }
  770.     } else {
  771.     if ((strncmp(current_object->name, "obj/", 4) != 0 &&
  772.         strncmp(current_object->name, "room/", 5) != 0 &&
  773.         strncmp(current_object->name, "std/", 4) != 0)
  774.         || !legal_path(file))
  775.         {
  776.         error("Illegal use of restore_object()\n");
  777.         }
  778.     }
  779. #endif /* NLHACK */
  780. #endif /* COMPAT_MODE */
  781.  
  782.     len = strlen(file);
  783.     name = (char *)alloca(len + 3);
  784.     (void)strcpy(name, file);
  785.     if (name[len-2] == '.' && name[len-1] == 'c')
  786.     name[len-1] = 'o';
  787.     else
  788.     (void)strcat(name, ".o");
  789.     f = fopen(name, "r");
  790. #ifndef mac
  791.     if (!f || fstat(fileno(f), &st) == -1) {
  792. #else
  793.     if (!f || stat(name, &st) == -1) {
  794. #endif
  795.     if (f) 
  796.         (void)fclose(f);
  797.     return 0;
  798.     }
  799.     if (st.st_size == 0) {
  800.     (void)fclose(f);
  801.     return 0;
  802.     }
  803.     val = (char *)alloca(st.st_size + 1);
  804.     buff = (char *)alloca(st.st_size + 1);
  805.     current_object = ob;
  806.     while(1) {
  807.     struct svalue *v;
  808.  
  809.     if (fgets(buff, st.st_size + 1, f) == 0)
  810.         break;
  811.     /* Remember that we have a newline at end of buff ! */
  812.     space = strchr(buff, ' ');
  813.     if (space == 0 || space - buff >= sizeof (var)) {
  814.         (void)fclose(f);
  815.         error("Illegal format when restore %s.\n", name);
  816.     }
  817.     (void)strncpy(var, buff, space - buff);
  818.     var[space - buff] = '\0';
  819.     (void)strcpy(val, space+1);
  820.     p = find_status(var, 0);
  821.     if (p == 0 || (p->type&TYPE_MOD_STATIC) || (p->type&TYPE_MOD_PRIVATE))
  822.         continue;
  823.     v = &ob->variables[p - ob->prog->variable_names];
  824.     if (val[0] == '"') {
  825.         val[strlen(val) - 2] = '\0';    /* Strip trailing "\n */
  826.         restore_newline(val+1);
  827.         free_svalue(v);
  828.         v->type = T_STRING;
  829.         v->u.string = string_copy(val+1);
  830.         v->string_type = STRING_MALLOC;
  831.         continue;
  832.     }
  833. /* Restore array: JnA 910520
  834. */
  835.     if (val[0] == '(') {
  836.         char *pt = val;
  837.         val[strlen(val) - 1] = '\0';    /* Strip trailing \n */
  838.         restore_newline(val+1);
  839.         free_svalue(v);
  840.         if (val[1] == '{') {
  841.         v->type = T_POINTER;
  842.         v->u.vec = restore_array(&pt);
  843.         } else {
  844.         v->type = T_MAPPING;
  845.         v->u.vec = restore_mapping(&pt);
  846.         }
  847.         if (!v->u.vec) {
  848.         *v = const0;
  849.         (void)fclose(f);
  850.            error("Illegal array/mapping format when restore %s.\n", name);
  851.         }
  852.         continue;
  853.     }
  854.  
  855.     free_svalue(v);
  856.     v->type = T_NUMBER;
  857.     v->u.number = atoi(val);
  858.     }
  859.     current_object = save;
  860.     if (d_flag > 1)
  861.     debug_message("Object %s restored from %s.\n", ob->name, name);
  862.     (void)fclose(f);
  863.     return 1;
  864. }
  865.  
  866. void tell_npc(ob, str)
  867.     struct object *ob;
  868.     char *str;
  869. {
  870.     push_constant_string(str);
  871.     (void)apply("catch_tell", ob, 1);
  872. }
  873.  
  874. /*
  875.  * Send a message to an object.
  876.  * If it is an interactive object, it will go to his
  877.  * screen. Otherwise, it will go to a local function
  878.  * catch_tell() in that object. This enables communications
  879.  * between players and NPC's, and between other NPC's.
  880.  */
  881. void tell_object(ob, str)
  882.     struct object *ob;
  883.     char *str;
  884. {
  885.     struct object *save_command_giver;
  886.  
  887.     if (ob->flags & O_DESTRUCTED)
  888.     return;
  889.     if (ob->interactive) {
  890.     save_command_giver = command_giver;
  891.     command_giver = ob;
  892.     add_message("%s", str);
  893.     command_giver = save_command_giver;
  894.     return;
  895.     }
  896.     tell_npc(ob, str);
  897. }
  898.  
  899. void free_object(ob, from)
  900.     struct object *ob;
  901.     char *from;
  902. {
  903.     struct sentence *s;
  904.  
  905.     ob->ref--;
  906.     if (d_flag > 1)
  907.     printf("Subtr ref to ob %s: %d (%s)\n", ob->name,
  908.               ob->ref, from);
  909.     if (ob->ref > 0)
  910.     return;
  911.     if (d_flag)
  912.     printf("free_object: %s.\n", ob->name);
  913.     if (!(ob->flags & O_DESTRUCTED)) {
  914.     /* This is fatal, and should never happen. */
  915.     fatal("FATAL: Object 0x%x %s ref count 0, but not destructed (from %s).\n",
  916.         ob, ob->name, from);
  917.     }
  918.     if (ob->interactive)
  919.     fatal("Tried to free an interactive object.\n");
  920.     /*
  921.      * If the program is freed, then we can also free the variable
  922.      * declarations.
  923.      */
  924.     if (ob->prog) {
  925.     tot_alloc_object_size -=
  926.         (ob->prog->num_variables - 1) * sizeof (struct svalue) +
  927.         sizeof (struct object);
  928.     free_prog(ob->prog, 1);
  929.     ob->prog = 0;
  930.     }
  931.     if (ob->swap_num != -1)
  932.     remove_swap_file(ob);
  933.     for (s = ob->sent; s;) {
  934.     struct sentence *next;
  935.     next = s->next;
  936.     free_sentence(s);
  937.     s = next;
  938.     }
  939.     if (ob->name) {
  940.     if (d_flag > 1)
  941.         debug_message("Free object %s\n", ob->name);
  942.     if (lookup_object_hash(ob->name) == ob)
  943.         fatal("Freeing object %s but name still in name table", ob->name);
  944.     xfree(ob->name);
  945.     ob->name = 0;
  946.     }
  947.     tot_alloc_object--;
  948.     xfree((char *)ob);
  949. }
  950.  
  951. void add_ref(ob, from)
  952.     struct object *ob;
  953.     char *from;
  954. {
  955.     ob->ref++;
  956.     if (d_flag > 1)
  957.     printf("Add reference to object %s: %d (%s)\n", ob->name,
  958.            ob->ref, from);
  959. }
  960.  
  961. /*
  962.  * Allocate an empty object, and set all variables to 0. Note that a
  963.  * 'struct object' already has space for one variable. So, if no variables
  964.  * are needed, we allocate a space that is smaller than 'struct object'. This
  965.  * unused (last) part must of course (and will not) be referenced.
  966.  */
  967. struct object *get_empty_object(num_var)
  968.     int num_var;
  969. {
  970.     static struct object NULL_object;
  971.     struct object *ob;
  972.     int size = sizeof (struct object) +
  973.     (num_var - !!num_var) * sizeof (struct svalue);
  974.     int i;
  975.  
  976.     tot_alloc_object++;
  977.     tot_alloc_object_size += size;
  978.     ob = (struct object *)xalloc(size);
  979.     /* marion
  980.      * Don't initialize via memset, this is incorrect. E.g. the bull machines
  981.      * have a (char *)0 which is not zero. We have structure assignment, so
  982.      * use it.
  983.      */
  984.     *ob = NULL_object;
  985.     ob->ref = 1;
  986.     ob->swap_num = -1;
  987.     for (i=0; i<num_var; i++)
  988.     ob->variables[i] = const0;
  989.     return ob;
  990. }
  991.  
  992. static void dest_object(struct object *ob)
  993. {
  994.     if (ob->flags & O_SWAPPED)
  995.         load_ob_from_swap(ob);
  996.     remove_object_from_stack(ob);
  997.     ob->flags |= O_DESTRUCTED;
  998.     remove_object_hash(ob);
  999.     destruct2(ob);
  1000. }
  1001.  
  1002. void remove_all_objects() {
  1003.     struct object *ob;
  1004.  
  1005.     remove_destructed_objects();
  1006.     while (obj_list) {
  1007.         ob = obj_list;
  1008.         dest_object(obj_list);
  1009.         obj_list = ob->next_all;
  1010.     }
  1011. }
  1012.  
  1013. #if 0
  1014. /*
  1015.  * For debugging purposes.
  1016.  */
  1017. void check_ob_ref(ob, from)
  1018.     struct object *ob;
  1019.     char *from;
  1020. {
  1021.     struct object *o;
  1022.     int i;
  1023.  
  1024.     for (o = obj_list, i=0; o; o = o->next_all) {
  1025.     if (o->inherit == ob)
  1026.         i++;
  1027.     }
  1028.     if (i+1 > ob->ref) {
  1029.     fatal("FATAL too many references to inherited object %s (%d) from %s.\n",
  1030.           ob->name, ob->ref, from);
  1031.     if (current_object)
  1032.         fprintf(stderr, "current_object: %s\n", current_object->name);
  1033.     for (o = obj_list; o; o = o->next_all) {
  1034.         if (o->inherit != ob)
  1035.         continue;
  1036.         fprintf(stderr, "  %s\n", ob->name);
  1037.     }
  1038.     }
  1039. }
  1040. #endif /* 0 */
  1041.  
  1042. struct object **hashed_living;
  1043.  
  1044. static int num_living_names, num_searches = 1, search_length = 1;
  1045.  
  1046. static int hash_living_name(str)
  1047.     char *str;
  1048. {
  1049. #if 1
  1050.     return hashstr(str, 100, LIVING_HASH_SIZE);
  1051. #else
  1052.     unsigned ret = 0;
  1053.  
  1054.     while(*str)
  1055.     ret = ret * 2 + *str++;
  1056.     return ret % LIVING_HASH_SIZE;
  1057. #endif
  1058. }
  1059.  
  1060. struct object *find_living_object(str, player)
  1061.     char *str;
  1062.     int player;
  1063. {
  1064.     struct object **obp, *tmp;
  1065.     struct object **hl;
  1066. #ifdef NLHACK
  1067.     int invis;
  1068.  
  1069.     invis = !command_giver || !(command_giver->flags & O_CAN_SEE_HINVIS);
  1070. #endif
  1071.     num_searches++;
  1072.     hl = &hashed_living[hash_living_name(str)];
  1073.     for (obp = hl; *obp; obp = &(*obp)->next_hashed_living) {
  1074.     search_length++;
  1075.     if (player && !((*obp)->flags & O_ONCE_INTERACTIVE))
  1076.         continue;
  1077. #ifdef NLHACK
  1078.     if (invis && ((*obp)->flags & O_HARD_INVIS))
  1079.         continue;
  1080. #endif
  1081.     if (!((*obp)->flags & O_ENABLE_COMMANDS))
  1082.         continue;
  1083.     if (strcmp((*obp)->living_name, str) == 0)
  1084.         break;
  1085.     }
  1086.     if (*obp == 0)
  1087.     return 0;
  1088.     /* Move the found ob first. */
  1089.     if (obp == hl)
  1090.     return *obp;
  1091.     tmp = *obp;
  1092.     *obp = tmp->next_hashed_living;
  1093.     tmp->next_hashed_living = *hl;
  1094.     *hl = tmp;
  1095.     return tmp;
  1096. }
  1097.  
  1098. void set_living_name(ob, str)
  1099.     struct object *ob;
  1100.     char *str;
  1101. {
  1102.     struct object **hl;
  1103.  
  1104.     if (ob->flags & O_DESTRUCTED)
  1105.     return;
  1106.     if (ob->living_name) {
  1107.     remove_living_name(ob);
  1108.     }
  1109.     num_living_names++;
  1110.     hl = &hashed_living[hash_living_name(str)];
  1111.     ob->next_hashed_living = *hl;
  1112.     *hl = ob;
  1113.     ob->living_name = make_shared_string(str);
  1114. #if 0    /* This is not a pretty way to find out if it is a wizard */
  1115.     if (ob->interactive) {
  1116.     struct svalue *v;
  1117.     
  1118.     v = apply("query_level", ob, 0);
  1119.     if (v && v->type == T_NUMBER && v->u.number >= 21)
  1120.         ob->flags |= O_IS_WIZARD;
  1121.     }
  1122. #endif
  1123.     return;
  1124. }
  1125.  
  1126. void remove_living_name(ob)
  1127.     struct object *ob;
  1128. {
  1129.     struct object **hl;
  1130.  
  1131. #ifdef MUDWHO
  1132.     sendmudwhologout(ob);
  1133. #endif
  1134.     num_living_names--;
  1135.     if (!ob->living_name)
  1136.     fatal("remove_living_name: no living name set.\n");
  1137.     hl = &hashed_living[hash_living_name(ob->living_name)];
  1138.     while(*hl) {
  1139.     if (*hl == ob)
  1140.         break;
  1141.     hl = &(*hl)->next_hashed_living;
  1142.     }
  1143.     if (*hl == 0)
  1144.     fatal("remove_living_name: Object named %s no in hash list.\n",
  1145.           ob->living_name);
  1146.     *hl = ob->next_hashed_living;
  1147.     free_string(ob->living_name);
  1148.     ob->next_hashed_living = 0;
  1149.     ob->living_name = 0;
  1150. }
  1151.  
  1152. void stat_living_objects() {
  1153.     add_message("Hash table of living objects:\n");
  1154.     add_message("-----------------------------\n");
  1155.     add_message("%d living named objects, average search length: %4.2f\n",
  1156.         num_living_names, (double)search_length / num_searches);
  1157. }
  1158.  
  1159. void reference_prog (progp, from)
  1160.     struct program *progp;
  1161.     char *from;
  1162. {
  1163.     progp->ref++;
  1164.     if (d_flag)
  1165.     printf("reference_prog: %s ref %d (%s)\n",
  1166.         progp->name, progp->ref, from);
  1167. }
  1168.  
  1169. /*
  1170.  * Decrement reference count for a program. If it is 0, then free the prgram.
  1171.  * The flag free_sub_strings tells if the propgram plus all used strings
  1172.  * should be freed. They normally are, except when objects are swapped,
  1173.  * as we want to be able to read the program in again from the swap area.
  1174.  * That means that strings are not swapped.
  1175.  */
  1176. void free_prog(progp, free_sub_strings)
  1177.     struct program *progp;
  1178.     int free_sub_strings;
  1179. {
  1180.     progp->ref--;
  1181.     if (progp->ref > 0)
  1182.     return;
  1183.     if (d_flag)
  1184.     printf("free_prog: %s\n", progp->name);
  1185.     if (progp->ref < 0)
  1186.     fatal("Negative ref count for prog ref.\n");
  1187.     total_prog_block_size -= progp->total_size;
  1188.     total_num_prog_blocks -= 1;
  1189.     if (free_sub_strings) {
  1190.     int i;
  1191.  
  1192.     /* Free all function names. */
  1193.     for (i=0; i < progp->num_functions; i++)
  1194.         if (progp->functions[i].name)
  1195.         free_string(progp->functions[i].name);
  1196.     /* Free all strings */
  1197.     for (i=0; i < progp->num_strings; i++)
  1198.         free_string(progp->strings[i]);
  1199.     /* Free all variable names */
  1200.     for (i=0; i < progp->num_variables; i++)
  1201.         free_string(progp->variable_names[i].name);
  1202.     /* Free all inherited objects */
  1203.     for (i=0; i < progp->num_inherited; i++)
  1204.         free_prog(progp->inherit[i].prog, 1);
  1205.     xfree(progp->name);
  1206.     }
  1207.     xfree((char *)progp);
  1208. }
  1209.  
  1210. void reset_object(ob, arg)
  1211.     struct object *ob;
  1212.     int arg;
  1213. {
  1214.     extern int current_time;
  1215.  
  1216.     /* Be sure to update time first ! */
  1217.     ob->next_reset = current_time + TIME_TO_RESET/2 +
  1218.     random_number(TIME_TO_RESET/2);
  1219. #ifdef COMPAT_MODE
  1220.     push_number(arg);
  1221.     (void)apply("reset", ob, 1);
  1222. #else
  1223.     if (arg == 0) {
  1224.     apply("__INIT", ob, 0);
  1225.     apply("create", ob, 0);
  1226.     } else {
  1227.     apply("reset", ob, 0);
  1228.     }
  1229. #endif    
  1230.     ob->flags |= O_RESET_STATE;
  1231. }
  1232.  
  1233. /*
  1234.  * If there is a shadow for this object, then the message should be
  1235.  * sent to it. But only if catch_tell() is defined. Beware that one of the
  1236.  * shadows may be the originator of the message, which means that we must
  1237.  * not send the message to that shadow, or any shadows in the linked list
  1238.  * before that shadow.
  1239.  */
  1240. int shadow_catch_message(ob, str)
  1241.     struct object *ob;
  1242.     char *str;
  1243. {
  1244.     if (!ob->shadowed)
  1245.     return 0;
  1246.     while(ob->shadowed != 0 && ob->shadowed != current_object)
  1247.     ob = ob->shadowed;
  1248.     while(ob->shadowing) {
  1249.     if (function_exists("catch_tell", ob))
  1250.     {
  1251.         push_constant_string(str);
  1252.         if (apply("catch_tell", ob, 1)) /* this will work, since we know the */
  1253.         /* function is defined */
  1254.         return 1;
  1255.     }
  1256.     ob = ob->shadowing;
  1257.     }
  1258.     return 0;
  1259. }
  1260.